/*
Copyright (C) 2022-2024 Inspur Corp.

SPDX-License-Identifier: Apache-2.0
*/
package proto

import (
	"github.com/golang/protobuf/proto"
	"github.com/pkg/errors"

	"git.cloud.inspur.com/ichain/ichain-protos-go/common"
	"git.cloud.inspur.com/ichain/ichain-protos-go/inode"
	"git.cloud.inspur.com/ichain/ichain-protos-go/ledger/rwset"
	"git.cloud.inspur.com/ichain/ichain-protos-go/ledger/rwset/kvrwset"
)

func GetPayload(e *common.Envelope) (*common.Payload, error) {
	payload := &common.Payload{}
	err := proto.Unmarshal(e.Payload, payload)
	return payload, errors.Wrap(err, "error unmarshaling Payload")
}

func GetChainHeader(bytes []byte) (*common.ChainHeader, error) {
	header := &common.ChainHeader{}
	err := proto.Unmarshal(bytes, header)
	return header, errors.Wrap(err, "error unmarshaling ChainHeader")
}

func GetTransaction(txBytes []byte) (*inode.Transaction, error) {
	tx := &inode.Transaction{}
	err := proto.Unmarshal(txBytes, tx)
	return tx, errors.Wrap(err, "error unmarshaling Transaction")
}

func GetContractActionPayload(capBytes []byte) (*inode.ContractActionPayload, error) {
	cap := &inode.ContractActionPayload{}
	err := proto.Unmarshal(capBytes, cap)
	return cap, errors.Wrap(err, "error unmarshaling ContractActionPayload")
}

func GetProposalResponsePayload(prpBytes []byte) (*inode.ProposalResponsePayload, error) {
	prp := &inode.ProposalResponsePayload{}
	err := proto.Unmarshal(prpBytes, prp)
	return prp, errors.Wrap(err, "error unmarshaling ProposalResponsePayload")
}

func GetContractAction(caBytes []byte) (*inode.ContractAction, error) {
	contractAction := &inode.ContractAction{}
	err := proto.Unmarshal(caBytes, contractAction)
	return contractAction, errors.Wrap(err, "error unmarshaling ContractAction")
}

func GetTxReadWriteSet(bytes []byte) (*rwset.TxReadWriteSet, error) {
	rwSet := &rwset.TxReadWriteSet{}
	err := proto.Unmarshal(bytes, rwSet)
	return rwSet, errors.Wrap(err, "error unmarshaling TxReadWriteSet")
}

func GetKVRWset(bytes []byte) (*kvrwset.KVRWSet, error) {
	rwSet := &kvrwset.KVRWSet{}
	err := proto.Unmarshal(bytes, rwSet)
	return rwSet, errors.Wrap(err, "error unmarshaling KVRWSet")
}

func GetWriteSetFromTransaction(tx *inode.Transaction) (*kvrwset.KVWrite, error) {
	actions := tx.GetActions()
	if len(actions) <= 0 {
		return nil, errors.New("the transaction has no actions!")
	}
	cap, err := GetContractActionPayload(actions[0].GetPayload())
	if err != nil {
		return nil, err
	}
	responsePayload, err := GetProposalResponsePayload(cap.Action.GetProposalResponsePayload())
	if err != nil {
		return nil, err
	}

	contractAction, err := GetContractAction(responsePayload.GetExtension())
	if err != nil {
		return nil, err
	}
	set, err := GetTxReadWriteSet(contractAction.GetResults())
	nsSet := set.GetNsRwset()
	if len(nsSet) <= 0 {
		return nil, errors.New("length of nsrwset is 0!")
	}
	writeSet := nsSet[len(nsSet)-1]
	rwSet, err := GetKVRWset(writeSet.GetRwset())
	if err != nil {
		return nil, err
	}

	write := rwSet.Writes[0]
	return write, nil
}
